using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.CodeDom.Compiler;

using NerdBank.HtmlScriptingClient;

namespace Lds.Ward.PhotoDirectory.Logic
{
	public class FamiliesToWebSite
	{
		private const string loginUrl = "https://secure.lds.org/units/login/0,8029,779-1,00.html";
		private const string adminDirectoryUrl = "https://secure.lds.org/units/a/admin/membership/1,8259,733-1-7-90123-{0}-true,00.html";
		private const string familyListingRegEx = @"\<td width=""40%"" align=""left"" valign=""top"" class=""featurestext""\>\<font color=""""\>{0}\<\/font\>\<br\>\<\/td\>"
			+ @"\s+\<td width=""40%"" rowspan=""2"" align=""left"" valign=""top"" class=""featurestext""\>\<font color=""""\>" 
			+ @"{2}\<br\>"
			+ @".+?\<a href=""([^""]+)"" class=""featureslink""\>change\<\/a\>";

		public delegate void UpdateStatusCallback(int percent);

		public static void Convert(IEnumerable<Family> families, DirectoryInfo photosDirectory,
			string username, string password, UpdateStatusCallback update)
		{
			if (families == null) throw new ArgumentNullException("families");
			if (photosDirectory == null) throw new ArgumentNullException("photosDirectory");

			CookieCollection cookies = new CookieCollection();
			HtmlForm form = HtmlForm.GetForm(new Uri(loginUrl), cookies);
			form.Fields["username"] = username;
			form.Fields["password"] = password;
			form.Fields["Submit"] = "Submit";
			HttpWebResponse response = form.Submit();
			if (response.StatusCode != HttpStatusCode.Redirect || response.Headers["Location"].StartsWith("/units/login"))
				throw new ApplicationException("Login failed.");
			cookies.Add(response.Cookies);
			int familyCount = 0;
			using (TempFileCollection tfc = new TempFileCollection())
			{
				tfc.KeepFiles = false;
				for (char firstLetter = 'A'; firstLetter <= 'Z'; firstLetter++)
				{
					response = HtmlClient.GetPage(string.Format(adminDirectoryUrl, firstLetter), cookies);
					cookies.Add(response.Cookies);
					string pageContent;
					using (StreamReader sr = new StreamReader(response.GetResponseStream()))
						pageContent = sr.ReadToEnd();

					foreach (Family fam in GetFamiliesWithLastNamesStartingWith(firstLetter, families))
					{
						if (update != null) update(familyCount++);
						string firstLineOfAddress = Regex.Match(fam.MailingAddress.Original, @"([^\n\r]+)").Groups[1].Value;
						string pattern = string.Format(familyListingRegEx, fam.Surname, fam.FamilyMembers[0].GivenNames, firstLineOfAddress);
						Match m = Regex.Match(pageContent, pattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
						if (!m.Success) continue; // family not found.  skipping
						string changeUrl = m.Groups[1].Value;
						form = HtmlForm.GetForm(adminDirectoryUrl, changeUrl, cookies);
						// Delete existing picture if there is one.
						Match oldPictureMatch = Regex.Match(form.HtmlContent, @"\<a href=""(/units/a/admin/membership/imagedelete/.+?\.html)"" class=""featureslink""\>Change\</a\>");
						if (oldPictureMatch.Success)
							form = HtmlForm.GetForm(adminDirectoryUrl, oldPictureMatch.Groups[1].Value, cookies);
						// Set the initial fields
						Match familyNumberMatch = Regex.Match(form.HtmlContent, @"document\.form\.FamilyNumber\.value = '(\w+)';");
						if (!familyNumberMatch.Success) throw new ApplicationException("Could not find family number.");
						form.Fields["FamilyNumber"] = familyNumberMatch.Groups[1].Value;
						form.Fields["RawUploadImageName"] = string.Format("{0}, {1}.jpg", fam.Surname, fam.FamilyMembers[0].GivenNames);
						form.Fields["Submit"] = "Submit";
						// Set up for photo upload
						form.Files["UploadImage"] = 
							fam.PreparePhoto(fam.GetPhotoPath(photosDirectory), tfc, MediaQuality.WardWebSite);
						// Submit changes
						response = form.Submit();
						if (response.StatusCode != HttpStatusCode.Found || !response.Headers["Location"].StartsWith("/units/a/admin/membership/"))
							throw new ApplicationException("Error submitting new photo.");
					}
				}
			}
		}

		private static IEnumerable<Family> GetFamiliesWithLastNamesStartingWith(char firstLetter, IEnumerable<Family> families)
		{
			ICollection<Family> list = new List<Family>();
			foreach (Family f in families)
				if (f.Surname.StartsWith(firstLetter.ToString()))
					list.Add(f);
			return list;
		}
	}
}
